package org.example.camundaapp.bpm.service;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.ProcessEngines;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.DeploymentBuilder;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;

/**
 * 部署到Camunda引擎
 * @className: CamundaDeployer
 * @author: ZHRJ
 * @date: 2025-06-24 11:34
 * @Version: 1.0
 * @description: 包含流程部署、启动等操作的工具类
 */

@Slf4j
public class CamundaDeployer {


    // 公共方法：获取默认流程引擎（避免重复调用）
    private ProcessEngine getProcessEngine() {
        return ProcessEngines.getDefaultProcessEngine();
    }


    /**
     * 部署流程到Camunda引擎
     * @param bpmnXml BPMN 文件的内容，作为字符串传入
     * @param processName 流程的名称，用于生成 .bpmn 文件名。
     */
    public Deployment deployProcess(String bpmnXml, String processName) {
        RepositoryService repositoryService = getProcessEngine().getRepositoryService();


        // 验证是否包含图形信息
        if (!bpmnXml.contains("<bpmndi:BPMNDiagram")) {
            throw new IllegalStateException("BPMN 不包含图形资源");
        }

        Deployment deployment = repositoryService.createDeployment()
                .name(processName)
                .addString(processName + ".bpmn", bpmnXml)
                .enableDuplicateFiltering(true) // 启用重复过滤
                .deploy();


        // 验证部署结果
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deployment.getId())
                .singleResult();

        if (definition.getDiagramResourceName() == null) {
            log.info("图表资源在部署期间未生成：{}", definition.getId());
            return deployment;
        }

        log.info("成功部署了带图表的进程: {}",
                definition.getDiagramResourceName());

        log.info("部署流程成功，id:{}；name:{}", deployment.getId(), deployment.getName());
        return deployment;
    }

    /**
     * 部署流程到Camunda引擎
     * @param bpmnXml BPMN 文件内容
     * @param pngBytes PNG 图片内容
     * @param processName 流程名称
     * @param processKey 流程定义的 key
     * @return
     */
    public Deployment deployProcess(String bpmnXml,byte[] pngBytes, String processName,String processKey) {
        RepositoryService repositoryService = getProcessEngine().getRepositoryService();

        if (!bpmnXml.contains("<bpmndi:BPMNDiagram")) {
            throw new IllegalStateException("BPMN 不包含图形资源");
        }

        // 资源名要与流程定义 key 一致
        String bpmnName = processKey + ".bpmn";
        String pngName = processKey + ".png";

        Deployment deployment = repositoryService.createDeployment()
                .name(processName)
                .addString(bpmnName, bpmnXml)
                .addInputStream(pngName, new ByteArrayInputStream(pngBytes))
                .deploy();

        // 可选：检查流程定义和图形资源
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deployment.getId())
                .singleResult();

        if (definition.getDiagramResourceName() == null) {
            throw new IllegalStateException("部署成功但未检测到流程图资源，检查资源名和流程定义key是否一致。");
        }


        log.info("成功部署了带图表的进程: {}",
                definition.getDiagramResourceName());

        log.info("部署流程成功，id:{}；name:{}", deployment.getId(), deployment.getName());
        return deployment;
    }

    /**
     * 部署流程到Camunda引擎
     * @param bpmnXml BPMN 文件的内容，作为字符串传入
     * @param processName 流程的名称，用于生成 .bpmn 文件名。
     * @param diagramResourceName 图形资源的名称（如 diagram.svg）。
     * @param diagramResourceStream 图形资源的输入流（可以为 null，表示不需要上传图形资源）
     * @return
     */
    public Deployment deployProcess(String bpmnXml, String processName, String diagramResourceName, InputStream diagramResourceStream) {
        RepositoryService repositoryService = getProcessEngine().getRepositoryService();

        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
                .addString(processName + ".bpmn", bpmnXml)
                .name(processName);

        // 添加图形资源（如果存在）
        if (diagramResourceStream != null && diagramResourceName != null) {
            deploymentBuilder.addInputStream(diagramResourceName, diagramResourceStream);
        }

        Deployment deployment = deploymentBuilder.deploy();
        log.info("部署流程成功，id:{}；name:{}", deployment.getId(), deployment.getName());
        return deployment;
    }

    // 使用camundaapi转换json为bpmn
    /*public String convertJsonToBpmnByCamundaApi(JSONObject json){
        BpmnModelInstance modelInstance = BpmnBuilder.build(json);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        Bpmn.writeModelToStream(outputStream, modelInstance);
        return outputStream.toByteArray();
    }*/

    // 通过读取bpmn文件部署流程实例
    public String deployProcess(String bpmnFilePath) {
        log.info("部署流程文件：{}", bpmnFilePath);
        RepositoryService repositoryService = getProcessEngine().getRepositoryService();
        try (java.io.InputStream bpmnStream = new java.io.FileInputStream(bpmnFilePath)) {
            Deployment deployment = repositoryService.createDeployment()
                    .addInputStream("process.bpmn", bpmnStream)
                    .deploy();
            log.info("部署流程成功，id:{} ；name:{}", deployment.getId(),deployment.getName());
            return deployment.getId();
        } catch (Exception e) {
            log.error("部署流程文件失败：{}", bpmnFilePath, e);
            return null;
        }
    }

    /**
     * 删除部署的流程实例
     * @param deploymentId
     */
    public void deleteDeployment(String deploymentId) {
        log.info("删除部署，部署id：{}", deploymentId);
        RepositoryService repositoryService = getProcessEngine().getRepositoryService();
        repositoryService.deleteDeployment(deploymentId, true);
    }

    /**
     * 启动流程实例
     * @param processDefinitionKey
     */
    public void startProcessInstance(String processDefinitionKey) {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        runtimeService.startProcessInstanceByKey(processDefinitionKey);
    }
}
